/**
 * Written by Jason Harwig as part of PDFjs React Outline Viewer
 * Source: https://codesandbox.io/s/rp18w
 */
import type { PDFDocumentProxy, RefProxy } from 'pdfjs-dist/types/src/display/api';
import type { Fit, FitB, FitBH, FitBV, FitH, FitR, FitV, PDFLocation, XYZ } from '../types';

function isRefProxy(obj: unknown): obj is RefProxy {
	return Boolean(typeof obj === 'object' && obj && 'gen' in obj && 'num' in obj);
}

async function getDestinationArray(doc: PDFDocumentProxy, dest: string | any[] | null): Promise<any[] | null> {
	return typeof dest === 'string' ? doc.getDestination(dest) : dest;
}

// eslint-disable-next-line @typescript-eslint/require-await
async function getDestinationRef(doc: PDFDocumentProxy, destArray: any[] | null): Promise<RefProxy | null> {
	if (destArray && isRefProxy(destArray[0])) return destArray[0];

	return null;
}

const isXYZ = (obj: { type: string; spec: number[] }): obj is XYZ => obj.type === 'XYZ' && obj.spec.length === 3;
const isFit = (obj: { type: string; spec: number[] }): obj is Fit => obj.type === 'Fit' && obj.spec.length === 0;
const isFitH = (obj: { type: string; spec: number[] }): obj is FitH => obj.type === 'FitH' && obj.spec.length === 1;
const isFitV = (obj: { type: string; spec: number[] }): obj is FitV => obj.type === 'FitV' && obj.spec.length === 1;
const isFitR = (obj: { type: string; spec: number[] }): obj is FitR => obj.type === 'FitR' && obj.spec.length === 4;
const isFitB = (obj: { type: string; spec: number[] }): obj is FitB => obj.type === 'FitB' && obj.spec.length === 0;
const isFitBH = (obj: { type: string; spec: number[] }): obj is FitBH => obj.type === 'FitBH' && obj.spec.length === 1;
const isFitBV = (obj: { type: string; spec: number[] }): obj is FitBV => obj.type === 'FitBV' && obj.spec.length === 1;

function getLocation(type: string, spec: number[]): PDFLocation | null {
	const obj = { type, spec };
	if (isXYZ(obj)) return obj;
	if (isFit(obj)) return obj;
	if (isFitH(obj)) return obj;
	if (isFitV(obj)) return obj;
	if (isFitR(obj)) return obj;
	if (isFitB(obj)) return obj;
	if (isFitBH(obj)) return obj;
	if (isFitBV(obj)) return obj;
	console.warn('no location type found for ', type, spec);

	return null;
}

const isSpecLike = (list: any[]): list is number[] => list && list.every((v) => !isNaN(v));

export { getDestinationArray, getDestinationRef, getLocation, isSpecLike };
